﻿using PhraseCorrector.DirectTanslate;
using PhraseCorrector.Init;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using static System.Net.Mime.MediaTypeNames;

namespace PhraseCorrector.SimplePinyin
{
    /**
     * 拼音转换类
     */
    public static class Pinyin
    {
        #region 获取术语拼音
        // /////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 取中文文本的拼音
        /// </summary>
        /// <param name="text">编码为UTF8的文本</param>
        /// <returns>返回中文文本的拼音</returns>
        public static string GetPinyin(string text)
        {
            if(string.IsNullOrWhiteSpace(text)) return "";
            return GetPinyin(text, new StringBuilder());
        }

        // /////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 获取汉字文本的拼音
        /// </summary>
        /// <param name="text">汉字文本</param>
        /// <param name="sbPinyin">用于存储拼音的StringBuilder</param>
        /// <returns>返回拼音字符串</returns>
        private static string GetPinyin(string text, StringBuilder sbPinyin)
        {
            // 遍历文本的每个字符，获取其拼音并追加到sbPinyin中
            for (var i= 0; i < text.Length; ++i)
                GetPinyin(GetPinyin(text[i]), sbPinyin, i);

            // 返回去除首尾空格的拼音字符串
            return sbPinyin.ToString().Trim();
        }

        // /////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 向StringBuilder中追加拼音字符并添加分隔空格
        /// </summary>
        /// <param name="py">拼音字符串</param>
        /// <param name="sbPinyin">用于存储拼音的StringBuilder</param>
        /// <param name="i">字符索引，本方法中未使用</param>
        private static void GetPinyin(string py, StringBuilder sbPinyin, int i)
        {
            // 如果拼音非空字符串，则追加到sbPinyin中
            if (py != "")
                sbPinyin.Append(ToSBC(py));
            // 追加一个空格作为拼音之间的分隔符
            sbPinyin.Append(' ');
        }

        #endregion

        #region 获取拼音对应的汉字
        // /////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 取和拼音相同的汉字列表
        /// </summary>
        /// <param name="pinyin">编码为UTF8的拼音</param>
        /// <returns>取拼音相同的汉字列表，如拼音“ai”将会返回“唉爱……”等</returns>
        public static string GetChineseText(string pinyin)
        {
            if (string.IsNullOrWhiteSpace(pinyin)) return string.Empty;
            string key = pinyin.Trim().ToLower();
            return GetChineseText(pinyin, key);
        }

        // /////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 根据拼音和关键字获取对应的中文文本
        /// </summary>
        /// <param name="pinyin">拼音字符串，用于在SPinyin.codes中进行搜索</param>
        /// <param name="key">关键字，用于精确搜索的标识</param>
        /// <returns>返回找到的中文文本，如果未找到则返回空字符串</returns>
        private static string GetChineseText(string pinyin, string key)
        {
            // 遍历SPinyin.codes中的每一项字符串
            foreach (var str in GetChineseList(pinyin))
                // 判断当前字符串是否以关键字加空格或冒号开头，如果是，则认为找到了对应的中文文本
                if (GetPinyin(str.Key)== pinyin)
                    // 返回文本内容，跳过前导的关键字和空格或冒号部分
                    return str.Key;

            // 如果遍历完成后仍未找到符合条件的字符串，返回空字符串
            return "";
        }

        // /////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 根据拼音获取对应的中文列表
        /// </summary>
        /// <param name="pinyin">输入的拼音字符串，单词之间用空格分隔</param>
        /// <returns>返回一个枚举，包含所有与拼音长度匹配的中文字符及其对应的拼音</returns>
        private static IEnumerable<KeyValuePair<string, string>> GetChineseList(string pinyin)
        {
            // 遍历SPinyin.codes中的每一项字符串
            return GetChineseList(pinyin.Split(' ').Length);
        }

        // /////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 获取指定拼音长度的中文字符列表
        /// </summary>
        /// <param name="lenth">拼音的长度</param>
        /// <returns>返回一个键值对列表，其中键是满足拼音长度的中文字符，值是其对应的英文翻译</returns>
        private static IEnumerable<KeyValuePair<string, string>> GetChineseList(int lenth)
        {
            // 在ChineseToEnglish.CElibrary字典中筛选出与拼音长度相同的中文字符
            return ChineseTraslator.CElibrary.Where(x=> x.Key.Length== lenth);
        }
        #endregion

        #region 获取单个字符的拼音代码

        // /////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 返回单个字符的汉字拼音
        /// </summary>
        /// <param name="ch">编码为UTF8的中文字符</param>
        /// <returns>ch对应的拼音</returns>
        private static string GetPinyin(char ch)
        {
            return GetPinyin(ch, GetHashIndex(ch));
        }

        // /////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 取文本索引值
        /// </summary>
        /// <param name="ch">字符</param>
        /// <returns>文本索引值</returns>
        private static short GetHashIndex(char ch)
        {
            return (short)((uint)ch % EmbeddedResources.codes.Length);
        }

        // /////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 获取字符的拼音
        /// </summary>
        /// <param name="ch">待转换的字符</param>
        /// <param name="hash">拼音哈希值，用于查找拼音表</param>
        /// <returns>返回字符的六位拼音代码，如果没有找到则返回字符本身</returns>
        private static string GetPinyin(char ch, short hash)
        {
            // 遍历哈希表中所有的拼音项
            for (var i= 0; i < EmbeddedResources.hashes[hash].Length; ++i)
                // 调用重载的GetPinyin方法，检查字符是否存在于特定的拼音项中
                if (GetPinyin(ch, hash, i) != -1)
                    // 如果找到，返回对应的拼音代码，取前6位并去除前后空格
                    return EmbeddedResources.codes[EmbeddedResources.hashes[hash][i]].Substring(0, 6).Trim();
            // 如果没有找到对应的拼音，返回字符本身
            return ch.ToString();
        }

        // /////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 检查字符是否存在于指定的拼音项中
        /// </summary>
        /// <param name="ch">待验证的字符</param>
        /// <param name="hash">拼音哈希值，用于查找拼音表</param>
        /// <param name="i">当前检查的拼音项索引</param>
        /// <returns>如果字符存在于指定的拼音项中，返回该项的索引；否则返回-1</returns>
        private static int GetPinyin(char ch, short hash, int i)
        {
            // 获取当前检查项的索引
            short index= EmbeddedResources.hashes[hash][i];
            // 检查字符是否存在于指定的拼音项中，搜索位置从第7位开始
            return EmbeddedResources.codes[index].IndexOf(ch, 7) != -1 ? index : -1;
        }

        // /////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 将输入字符串中的全角字符转换为半角字符
        /// </summary>
        /// <param name="input">待转换的字符串</param>
        /// <returns>转换后的字符串</returns>
        public static string ToSBC(string input)
        {
            return LoopToSBC(input.ToCharArray());
        }

        // /////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 将字符数组中的全角字符转换为半角字符，并返回新的字符串
        /// </summary>
        /// <param name="chars">包含全角字符的字符数组</param>
        /// <returns>转换后的半角字符组成的字符串</returns>
        public static string LoopToSBC(char[] chars)
        {
            // 遍历字符数组，对每个字符进行全角到半角的转换
            for (int i= 0; i < chars.Length; i++)
                CharToSBC(chars, i);
            // 使用转换后的字符数组创建并返回一个新的字符串
            return new string(chars);
        }
        
        // /////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 将字符数组中的指定字符进行全角到半角的转换
        /// </summary>
        /// <param name="chars">字符数组</param>
        /// <param name="i">字符在数组中的索引</param>
        public static void CharToSBC(char[] chars, int i)
        {
            if (chars[i]== (char)12288) // 全角空格转半角空格
                chars[i]= (char)32;
            else
                OtherCharToSBC(ref chars, i); // 其他全角字符转半角
        }

        // /////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 将其他全角字符转换为半角字符
        /// </summary>
        /// <param name="chars">字符数组，包含待转换的全角字符</param>
        /// <param name="i">索引，用于定位字符数组中待转换的字符</param>
        public static void OtherCharToSBC(ref char[] chars, int i)
        {
            // 判断字符是否在全角字符的Unicode范围之内
            if (chars[i] > (char)65280 && chars[i] < (char)65375)
            {
                // 将全角字符转换为半角字符
                chars[i]= (char)(chars[i] - 65248);
            }
        }
        #endregion
    }
}
